package srdb.migration.dbhandler.sqlserver;

import srdb.migration.common.MTKGenericTransformDDL;
import srdb.migration.schema.metadata.Function;
import srdb.migration.schema.metadata.Procedure;
import srdb.migration.schema.metadata.Synonym;
import srdb.migration.schema.metadata.Trigger;
import srdb.migration.schema.metadata.View;

public class SQLServerTransformDDL extends MTKGenericTransformDDL {
	public String getCreateScript(View view) {
		String sql = replaceNames(view.getSQL(), getSourceToTargetNames());
		sql = sql + "\n";

		return sql;
	}

	public String getCreateScript(Trigger trigger) {
		String sql = replaceNames(trigger.getBody(), getSourceToTargetNames());
		sql = sql + "\n";

		return sql;
	}

	public String getCreateScript(Procedure proc) {
		String sql = replaceNames(proc.getSQL(), getSourceToTargetNames());

		String[] parts = splitHeaderAndBody(sql);
		parts[1] = (" $$ " + parts[1] + " $$\n LANGUAGE 'pltsql'");
		return parts[0] + parts[1];
	}

	public String getCreateScript(Function func) {
		String sql = replaceNames(func.getSQL(), getSourceToTargetNames());

		String[] parts = splitHeaderAndBody(sql);
		parts[1] = (" $$ " + parts[1] + " $$\n LANGUAGE 'pltsql'");
		return parts[0] + parts[1];
	}

	private String[] splitHeaderAndBody(String text) {
		int index = 0;
		int optionNum = 0;
		String header = "";
		String comments = "";
		boolean needToAddParenthesis = false;

		comments = skipComments(text, index);
		header = header + comments;
		index += comments.length();
		String msg = nextWord(text, index);
		if (getMatchOption(new String[] { "CREATE" }, msg) == -1)
			illegalBlock();
		header = header + msg;
		index += msg.length();

		comments = skipComments(text, index);
		header = header + comments;
		index += comments.length();
		msg = nextWord(text, index);
		if ((optionNum = getMatchOption(new String[] { "OR", "FUNCTION",
				"PROCEDURE", "PROC" }, msg)) == -1)
			illegalBlock();
		header = header + msg;
		index += msg.length();
		if (optionNum == 0) {
			comments = skipComments(text, index);
			header = header + comments;
			index += comments.length();
			msg = nextWord(text, index);
			if (getMatchOption(new String[] { "REPLACE" }, msg) == -1)
				illegalBlock();
			header = header + msg;
			index += msg.length();

			comments = skipComments(text, index);
			header = header + comments;
			index += comments.length();
			msg = nextWord(text, index);
			if ((optionNum = getMatchOption(new String[] { "PROCEDURE",
					"FUNCTION", "PROC" }, msg)) == -1)
				illegalBlock();
			header = header + msg;
			index += msg.length();
		}

		comments = skipComments(text, index);
		header = header + comments;
		index += comments.length();
		msg = nextWord(text, index);
		header = header + msg;
		index += msg.length();

		if (!nameContainsParenthesis(msg)) {
			comments = skipComments(text, index);
			header = header + comments;
			index += comments.length();
			msg = nextWord(text, index);
			if (!msg.trim().startsWith("("))
				if (getMatchOption(new String[] { "RETURNS", "AS", "BEGIN" },
						msg) == -1) {
					needToAddParenthesis = true;
					header = header + " ( ";
					header = header + msg;
					index += msg.length();
				}
			do {
				comments = skipComments(text, index);
				header = header + comments;
				index += comments.length();
				msg = nextWord(text, index);
				optionNum = getMatchOption(new String[] { "RETURNS", "BEGIN",
						"AS" }, msg);
				if (optionNum == -1) {
					header = header + msg;
					index += msg.length();
				} else if (needToAddParenthesis) {
					header = header + " ) ";
				}
			} while (optionNum == -1);
		}
		do {
			comments = skipComments(text, index);
			header = header + comments;
			index += comments.length();
			msg = nextWord(text, index);
			optionNum = getMatchOption(new String[] { "BEGIN", "AS" }, msg);
			if (optionNum != 0) {
				header = header + msg;
				index += msg.length();
			} else {
				header = header + " AS ";
			}
		} while (optionNum == -1);

		return new String[] { header, text.substring(index) };
	}

	private String nextWord(String data, int offset) {
		int counter = offset;
		while ((counter < data.length())
				&& (Character.isWhitespace(data.charAt(counter)))) {
			counter++;
		}
		boolean stop = false;
		boolean inDoubleQuotes = false;
		boolean inSingleQuotes = false;
		while ((!stop) && (counter < data.length())) {
			char c = data.charAt(counter);
			if (c == '"') {
				inDoubleQuotes = !inDoubleQuotes;
				counter++;
			} else if (c == '\'') {
				inSingleQuotes = !inSingleQuotes;
				counter++;
			} else if ((!inSingleQuotes) && (!inDoubleQuotes)
					&& (Character.isWhitespace(c))) {
				stop = true;
			} else {
				counter++;
			}
		}

		return data.substring(offset, counter);
	}

	private int getMatchOption(String[] choices, String actual) {
		if ((choices == null) || (actual == null)) {
			return -1;
		}
		for (int i = 0; i < choices.length; i++) {
			if (actual.trim().equalsIgnoreCase(choices[i].trim())) {
				return i;
			}
		}
		return -1;
	}

	private String skipComments(String data, int offset) {
		String msg = "";
		String comments = "";
		while ((msg = nextComment(data, offset)).length() > 0) {
			comments = comments + msg;
			offset += msg.length();
		}
		return comments;
	}

	private String nextComment(String data, int offset) {
		int counter = offset;
		boolean hasComments = false;

		while ((counter < data.length())
				&& (Character.isWhitespace(data.charAt(counter))))
			counter++;
		if ((counter < data.length() - 2) && (data.charAt(counter) == '/')
				&& (data.charAt(counter + 1) == '*')) {
			hasComments = true;

			counter += 2;
		}
		while ((counter < data.length())
				&& ((data.charAt(counter) != '/') || (data.charAt(counter - 1) != '*'))) {
			
			if ((counter >= data.length() - 2) || (data.charAt(counter) != '-')
					|| (data.charAt(counter + 1) != '-'))
				break;
			hasComments = true;
			counter++;
			continue;
			
		}
		while ((counter < data.length()) && (data.charAt(counter) != '\n')) {
			counter++;
		}
		if (hasComments)
			return data.substring(offset, counter + 1);
		return "";
	}

	private void illegalBlock() throws IllegalArgumentException {
		throw new IllegalArgumentException(
				"Given text is not a valid T-SQL block");
	}

	private boolean nameContainsParenthesis(String name) {
		boolean inSingleQuotes = false;
		boolean inDoubleQuotes = false;
		for (int i = 0; i < name.length(); i++) {
			char c = name.charAt(i);
			switch (c) {
			case '\'':
				inSingleQuotes = !inSingleQuotes;
				break;
			case '"':
				inDoubleQuotes = !inDoubleQuotes;
				break;
			case '(':
				if ((inSingleQuotes) || (inDoubleQuotes))
					continue;
				return true;
			}
		}
		return false;
	}

	public String getCreateScript(Synonym syn) {
		String sql = "CREATE SYNONYM " + syn.getSchema() + "." + syn.getName()
				+ " FOR " + syn.getSynobjname();

		sql = sql + "\n";

		return replaceNames(sql, getSourceToTargetNames());
	}
}

/*

 */